package cn.kmsoft.stgeometry.util;


import cn.kmsoft.stgeometry.constant.GeometryFormat;
import cn.kmsoft.stgeometry.constant.GeometryType;
import com.esri.core.geometry.*;
import com.esri.core.geometry.Geometry.Type;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 各种格式的数据转换为wkt
 *
 * 目前支持如下格式
 * esrijson
 * geojson
 * wkt
 * 坐标串 extent xmin,ymin,xmax,ymax
 * esrijson extent
 *
 * @author gisuser
 */
public class GeomUtil {

    private static OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance();

    public static String geomToWkt(String geometry, GeometryType geometryType) throws Exception {
        GeometryFormat formatType = geometryType.getFormatType();
        String wkt = "";
        switch (formatType) {
            case ESRI:
                wkt = esrijsonToWkt(geometry);
                break;
            case ESRIExtent:
                wkt = esriExtentToWkt(geometry);
                break;
            case GEOJSON:
                wkt = geojsonToWkt(geometry);
                break;
            case WKT:
                wkt = geometry;
                break;
            case GISUNI:
                wkt = gisuniExtentToWkt(geometry);
                break;
            case Circle:
                wkt = circleToWkt(geometry);
                break;
            default:
                throw new Exception("不支持的几何对象");
        }
        return wkt;
    }

    /**
     * Esrijson to wkt.
     *
     * @param geometry the geometry
     * @return the string
     * @throws JSONException the JSON exception
     */
    public static String esrijsonToWkt(String geometry) throws JSONException {
        JsonFactory factory = new JsonFactory();
        JsonParser jsonParserPt = null;
        try {
            jsonParserPt = factory.createJsonParser(geometry);
            jsonParserPt.nextToken();
        } catch (IOException e) {
            // JsonParseException继承自IOException，只写一个
            throw new JSONException(e.getMessage());
        }
        Geometry geom = GeometryEngine.jsonToGeometry(jsonParserPt).getGeometry();
        return GeometryEngine.geometryToWkt(geom, 0);
    }

    /**
     * Gojson to wkt.
     *
     * @param value the value
     * @return the string
     * @throws JSONException the JSON exception
     */
    public static String geojsonToWkt(String value) throws JSONException {
        JSONObject json = new JSONObject(value);
        json.remove("crs");
        MapGeometry mapGeometry = GeometryEngine.geometryFromGeoJson(json.toString(), GeoJsonImportFlags.geoJsonImportDefaults,
                Type.Unknown);
        return GeometryEngine.geometryToWkt(mapGeometry.getGeometry(), WktExportFlags.wktExportDefaults);
    }

    public static String wktToEsriJson(String value, int wkid) {
        Geometry geometry = GeometryEngine.geometryFromWkt(value, WktImportFlags.wktImportDefaults, Type.Unknown);
        return GeometryEngine.geometryToJson(wkid, geometry);
    }

    public static String wktToGeoJson(String value, int wkid) {
        Geometry geometry = GeometryEngine.geometryFromWkt(value, WktImportFlags.wktImportDefaults, Type.Unknown);
        return GeometryEngine.geometryToGeoJson(wkid, geometry);
    }

    /**
     * esriGeometryEnvelope类型转wkt.
     *
     * @param value the value
     * @return the string
     * @throws JSONException the JSON exception
     */
    public static String esriExtentToWkt(String value) throws JSONException {
        JSONObject extent = new JSONObject(value);
        double xmin = extent.getDouble("xmin");
        double ymin = extent.getDouble("ymin");
        double xmax = extent.getDouble("xmax");
        double ymax = extent.getDouble("ymax");
        return extentCoordsToWkt(xmin, ymin, xmax, ymax);
    }

    private static String extentCoordsToWkt(double xmin, double ymin, double xmax, double ymax) {
        Envelope envelope = new Envelope();
        envelope.setCoords(xmin, ymin, xmax, ymax);
        return GeometryEngine.geometryToWkt(envelope, WktExportFlags.wktExportDefaults);
    }

    /**
     * 简化的extent表述方式
     * xmin,ymin,xmax,ymax
     *
     * @param value
     * @return
     */
    public static String gisuniExtentToWkt(String value) {
        String[] coords = value.split(",");
        double xmin = Double.parseDouble(coords[0]);
        double ymin = Double.parseDouble(coords[1]);
        double xmax = Double.parseDouble(coords[2]);
        double ymax = Double.parseDouble(coords[3]);
        return extentCoordsToWkt(xmin, ymin, xmax, ymax);
    }

    /**
     * 包含中心点及半径的圆解析成wkt
     *
     * @return
     */
    public static String circleToWkt(String value) {
        JSONObject circle = new JSONObject(value);
        double x = circle.getDouble("x");
        double y = circle.getDouble("y");
        double radius = circle.getDouble("radius");
        int wkid = 4523;
        if (circle.has("wkid")) {
            wkid = circle.getInt("wkid");
        }
        //st_buffer(st_setsrid(st_makepoint(113.19981,22.61104),4523), 0.001)
        return "st_buffer(st_setsrid(st_makepoint(" + x + "," + y + ")," + wkid + ")," + radius + ")";
    }

    /**
     * wkt转wkb
     *
     * @param wkt
     * @return
     */
    public static byte[] wkt2Wkb(String wkt) {
        try {
            Geometry geometry = GeometryEngine.geometryFromWkt(wkt, WktImportFlags.wktImportDefaults, Type.Unknown);
            OperatorExportToWkb exporter = (OperatorExportToWkb) factory.getOperator(Operator.Type.ExportToWkb);
            ByteBuffer byteBuffer = exporter.execute(WkbExportFlags.wkbExportDefaults, geometry, null);
            byte[] returnbyte = byteBuffer.array();
            byteBuffer.clear();
            return returnbyte;
        } catch (IllegalArgumentException e) {

        }
        return null;
    }
}
